#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qingtian.h"
#include "msg_structure.h"
#include "enclave_log.h"

extern const cc_ecall_func_t cc_ecall_tables[];
extern const size_t ecall_table_size;

cc_enclave_result_t handle_ecall_function(
    const uint8_t *input_buffer,
    size_t input_buffer_size,
    uint8_t **output_buffer,
    size_t *output_bytes_written)
{
    cc_enclave_result_t result_cc = CC_SUCCESS;
    // write nothing default
    *output_bytes_written = 0;
    if (input_buffer == NULL || input_buffer_size == 0 || output_buffer == NULL || output_bytes_written == NULL) {
        return CC_ERROR_BAD_PARAMETERS;
    }
#if 1
    printf("handle ecall received(%zu): ", input_buffer_size);
    for (int i = 0; i < input_buffer_size; i++) {
        printf("%02X", input_buffer[i]);
    }
    printf("\n");
#endif
    uint8_t *out_buf = NULL;
    msg_t msg_unpacked;
    msg_unpacked.buf = NULL;
    msg_unpacked.buf_size = 0;
    int ret = unpack_msg(&msg_unpacked, input_buffer, input_buffer_size);
    if (ret == -1) {
        result_cc = CC_ERROR_SHORT_BUFFER;
        print_error_term("unpack message error: short buffer(%lu)\n", result_cc);
        goto end;
    } else if (ret == -2) {
        result_cc =  CC_ERROR_BAD_FORMAT;
        print_error_term("unpack message error: bad format(%lu)\n", result_cc);
        goto end;
    }
    cc_ecall_func_t func;
    enclave_table_t ecall_table;
    ecall_table.ecalls = cc_ecall_tables;
    ecall_table.num = ecall_table_size;
    if (msg_unpacked.function_id >= ecall_table.num) {
        result_cc = CC_ERROR_ECALL_NOT_ALLOWED;
        print_error_term("function id(%lu) not found(%lu), ecall table size = %zu\n", msg_unpacked.function_id, result_cc, ecall_table_size);
        goto end;
    }
    func = ecall_table.ecalls[msg_unpacked.function_id];
    if (func == NULL) {
        result_cc = CC_ERROR_ITEM_NOT_FOUND;
        print_error_term("ecall function not found(%lu)\n", result_cc);
        goto end;
    }
    if (msg_unpacked.out_buf_size != 0) {
        out_buf = calloc(1, msg_unpacked.out_buf_size);
        if (out_buf == NULL) {
            result_cc = CC_ERROR_SHORT_BUFFER;
            print_error_term("short buffer(%lu)\n", result_cc);
            goto end;
        }
    }
    size_t write_len = 0;
    result_cc = func(msg_unpacked.buf, msg_unpacked.buf_size, out_buf,
                    msg_unpacked.out_buf_size, &write_len);

    msg_t msg_out;
    msg_out.function_id = msg_unpacked.function_id;
    msg_out.buf = out_buf;
    msg_out.buf_size = write_len;
    msg_out.out_buf_size = msg_unpacked.out_buf_size;//copy raw size

    size_t send_buf_length = MSG_BUF_SIZE(msg_out.buf_size);
    uint8_t *send_buf = calloc(1, send_buf_length);
    if (send_buf == NULL) {
        result_cc = CC_ERROR_SHORT_BUFFER;
        print_error_term("short buffer(%lu)\n", result_cc);
        goto end;
    }
    ret = pack_msg(send_buf, send_buf_length, &msg_out);
    if (ret <= 0) {
        free(send_buf);
        result_cc = CC_ERROR_SHORT_BUFFER;
        print_error_term("short buffer(%lu)\n", result_cc);
        goto end;
    }
    result_cc = CC_SUCCESS;
    *output_buffer = send_buf;
    *output_bytes_written = ret;
#if 1
    printf("handle ecall send(%d): ", ret);
    for (int i = 0; i < ret; i++) {
        printf("%02X", send_buf[i]);
    }
    printf("\n");
#endif
end:
    if (out_buf != NULL) {
        free(out_buf);
    }
    if (msg_unpacked.buf != NULL) {
        free(msg_unpacked.buf);
    }
    return result_cc;
}